//----------------------------------------------------------------------------
//  ,-.
// /_\___ ,   Ninja Framework
// '  ___\    (C) Riccardo Capra - http://riccar.do
//  //   \\
//----------------------------------------------------------------------------
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
//----------------------------------------------------------------------------

#include "NjExample01.h"
#include "NjSynchronizationStats.h"
#include "NjPlatformSyncObject.h"

//----------------------------------------------------------------------------
class NjSynchronizationStats::Static
{
public:
	static void Initialize();

	static const NjUint TOT_CELLS=TOT_ROWS*TOT_COLUMNS;

	struct Cell
	{
		NjUint m_uSumOne;
		NjFloat m_fSumX;
		NjFloat m_fSumXX;
	};

	static NjBool m_bInitialized;
	static Cell n_aCells[TOT_CELLS];
	static NjCharA const * const m_aColumns[TOT_COLUMNS];
	static NjCharA const * const m_aRows[TOT_ROWS];

	NJ_DISABLE_INSTANCE(Static);
};
//----------------------------------------------------------------------------
void NjSynchronizationStats::Store(Row eRow, Column eColumn, NjUint uCount, NjFloat fValue)
{
	Static::Initialize();

	NjUint const uIndex(eRow*TOT_COLUMNS+eColumn);
	Static::Cell & kCell(Static::n_aCells[uIndex]);

	kCell.m_uSumOne+=uCount;
	kCell.m_fSumX+=fValue;
	fValue*=fValue;
	kCell.m_fSumXX+=fValue;
}
//----------------------------------------------------------------------------
void NjSynchronizationStats::Dump()
{
	if (!Static::m_bInitialized)
		return;

	printf("|| %s ||",
#if NJ_PLATFORM_OS_WIN
		"Win"
#elif NJ_PLATFORM_OS_LINUX
		"Linux"
#else
#		error "Not supported platform"
#endif
#if NJ_PLATFORM_ASM_INTEL_X86
		" x86"
#elif NJ_PLATFORM_ASM_INTEL_X64
		" x64"
#elif NJ_PLATFORM_ASM_ARM_V6K
		" armv6k"
#else
#	error "Unsupported build configuration"
#endif
#if defined(NJ_CONFIGURATION_DEBUG)
		" DEBUG"
#elif defined(NJ_CONFIGURATION_RELEASE)
		" RELEASE"
#elif defined(NJ_CONFIGURATION_SHIPPING)
		" SHIPPING"
#endif
		);

	NjUint uTotColumns(TOT_COLUMNS);
	NjCharA const * const * pText=Static::m_aColumns;
	while (uTotColumns>0)
	{
		--uTotColumns;
		printf(" %s ||", *pText);
		++pText;
	}

	Static::Cell * pCell(Static::n_aCells);
	NjUint uTotRows(TOT_ROWS);
	pText=Static::m_aRows;

	while (uTotRows>0)
	{
		--uTotRows;

		NjCharA const * szRow(*pText);
		++pText;

		if (szRow==NJ_NULL)
			szRow=NjPlatformSyncObject::GetName();

		printf("\n|| %s ||", szRow);

		uTotColumns=TOT_COLUMNS;
		while (uTotColumns>0)
		{
			if (pCell->m_uSumOne<1)
				printf(" ||");
			else
			{
				NjFloat fValue(pCell->m_fSumX/NjFloat(pCell->m_uSumOne));

				if (uTotColumns==TOT_COLUMNS)
					printf(" %d b ||", NjUint32(fValue));
				else
				{
					if (fValue<0)
						fValue=0;
					else
						fValue=NjFloat(NjUint(fValue*1000*1000*1000*10+NjFloat(0.5)))/10;
					printf(" %6.2f ns ||", fValue);
				}
			}

			--uTotColumns;

			++pCell;
		}
	}

	printf("\n");
}
//----------------------------------------------------------------------------
void NjSynchronizationStats::Static::Initialize(void)
{
	if (m_bInitialized)
		return;

	m_bInitialized=NJ_TRUE;

	Cell * pCell(n_aCells+NJ_LENGTH_OF(n_aCells));
	while (pCell>n_aCells)
	{
		--pCell;
		pCell->m_uSumOne=0;
		pCell->m_fSumX=0;
		pCell->m_fSumXX=0;
	}
}
//----------------------------------------------------------------------------
NjBool NjSynchronizationStats::Static::m_bInitialized(NJ_FALSE);
NjSynchronizationStats::Static::Cell NjSynchronizationStats::Static::n_aCells[TOT_CELLS];
NjCharA const * const NjSynchronizationStats::Static::m_aColumns[TOT_COLUMNS]={
	"Size",
	"Creation",
	"Destruction",
	"`Lock`",
	"`Unlock`",
	"`TryLock(0)` (success)",
	"`TryLock(0)` (fail)",
	"`Set`",
	"`Unset`",
	"`WakeOne`",
	"`WakeAll`",
	"`TryWait` (success)",
	"`TryWait` (fail)"
};
NjCharA const * const NjSynchronizationStats::Static::m_aRows[TOT_ROWS]={
	NJ_NULL,
	"`NjMutex`",
	"`NjRecursiveMutex`",
	"`NjSemaphore`",
	"`NjRWLock`",
	"`NjRWLock` (read)",
	"`NjRWLock` (write)",
	"`NjEvent`",
	"`NjPulseEvent`",
	"`NjDummySyncObject`"
};
//----------------------------------------------------------------------------
